package com.code.soulnetty.modbus.client.service;

import com.code.soulnetty.modbus.biz.resp.CommonDeviceData;
import com.code.soulnetty.modbus.biz.resp.ProtocolReadResponse;
import com.code.soulnetty.modbus.client.message.ProtocolRequestWrap;
import com.code.soulnetty.modbus.client.message.ProtocolResponse;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lyf
 * @date 2022-12-17 11:43
 */
@Slf4j
@Component
public class ProtocolResponseService {

    /**
     * 保存设备的数据
     */
    private Map<Class, Map<Integer, Map<String, CommonDeviceData>>> pointDataPeriodCache = new ConcurrentHashMap<>();

    public void handler(ProtocolRequestWrap request, ProtocolResponse response) {
        if (!response.isSuccess()) {
            // 响应失败
            log.error("[CHANNEL] [ERR_RES] {},{}", ByteBufUtil.hexDump(request.requestByteData()), response);
            return;
        }

        try {
            handler((ProtocolReadResponse) response);
        } catch (Exception e) {
            log.error("[CHANNEL] [RESPONSE] handle response error !!!", e);
        }
    }

    private void handler(ProtocolReadResponse response) {
        final List<CommonDeviceData> data = response.getData();
        List<CommonDeviceData> sendData = new ArrayList<>(16);
        for (CommonDeviceData deviceData : data) {
            // 把返回所有的完整点位的设备数据 过滤出来并返回
            sendData(deviceData, sendData);
        }

        // 此处得到的就是完整的点位数据了
        log.info("receive full data: {}", sendData);

    }

    private void sendData(CommonDeviceData deviceData, List<CommonDeviceData> sendData) {
        final CommonDeviceData newDeviceData = getPeriodData(deviceData);
        newDeviceData.add(deviceData);
        if (newDeviceData.getNeedPointCount() <= newDeviceData.getPoints().size()) {
            CommonDeviceData remove = remove(newDeviceData);
            if (remove != null) {
                sendData.add(remove);
            }
        }
    }

    private CommonDeviceData remove(CommonDeviceData data) {
        return pointDataPeriodCache.get(data.getClass()).get(data.getPeriod()).remove(data.getGuid());
    }

    private CommonDeviceData getPeriodData(CommonDeviceData deviceData) {
        Map<Integer, Map<String, CommonDeviceData>> pointData = pointDataPeriodCache.get(deviceData.getClass());
        if (pointData == null) {
            throw new RuntimeException("Unrecognized protocol type device");
        }
        int period = deviceData.getPeriod();
        Map<String, CommonDeviceData> periodMap = pointData.get(period);
        if (periodMap != null) {
            CommonDeviceData data = periodMap.get(deviceData.getGuid());
            if (data != null) {
                return data;
            }
        }
        synchronized (pointData) {
            periodMap = pointData.get(period);
            if (periodMap == null) {
                periodMap = new ConcurrentHashMap<>();
            } else {
                CommonDeviceData data1 = periodMap.get(deviceData.getGuid());
                if (data1 != null) {
                    return data1;
                }
            }
            CommonDeviceData data;
            try {
                data = deviceData.getClass().newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            data.setNeedPointCount(deviceData.getNeedPointCount());
            data.setPeriod(deviceData.getPeriod());
            data.setTenantId(deviceData.getTenantId());
            data.setGuid(deviceData.getGuid());
            data.setPoints(new ArrayList<>());
            periodMap.put(data.getGuid(), data);
            pointData.put(period, periodMap);
            return data;
        }

    }
}
